home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / mktty / RCS / mktty.c,v < prev    next >
Encoding:
Text File  |  1989-06-15  |  12.5 KB  |  537 lines

  1. head     1.2;
  2. branch   ;
  3. access   ;
  4. symbols  ;
  5. locks    ; strict;
  6. comment  @ * @;
  7.  
  8.  
  9. 1.2
  10. date     89.06.15.10.50.36;  author ouster;  state Exp;
  11. branches ;
  12. next     1.1;
  13.  
  14. 1.1
  15. date     89.04.06.15.11.32;  author ouster;  state Exp;
  16. branches ;
  17. next     ;
  18.  
  19.  
  20. desc
  21. @@
  22.  
  23.  
  24. 1.2
  25. log
  26. @Use non-blocking I/O for raw terminal.
  27. @
  28. text
  29. @/* 
  30.  * mktty.c --
  31.  *
  32.  *    Main program for the "mktty" program.  Provides a linkup between
  33.  *    a pseudo-device with an attached tty driver and a raw terminal
  34.  *    device.  Also allows a network TCP connection to be used in
  35.  *    place of the raw terminal device.
  36.  *
  37.  * Copyright 1987, 1988 Regents of the University of California
  38.  * Permission to use, copy, modify, and distribute this
  39.  * software and its documentation for any purpose and without
  40.  * fee is hereby granted, provided that the above copyright
  41.  * notice appear in all copies.  The University of California
  42.  * makes no representations about the suitability of this
  43.  * software for any purpose.  It is provided "as is" without
  44.  * express or implied warranty.
  45.  */
  46.  
  47. #ifndef lint
  48. static char rcsid[] = "$Header: /a/newcmds/mktty/RCS/mktty.c,v 1.1 89/04/06 15:11:32 ouster Exp $ SPRITE (Berkeley)";
  49. #endif not lint
  50.  
  51. #include <sprite.h>
  52. #include <bstring.h>
  53. #include <errno.h>
  54. #include <fcntl.h>
  55. #include <fs.h>
  56. #include <netdb.h>
  57. #include <pdev.h>
  58. #include <sgtty.h>
  59. #include <stdio.h>
  60. #include <stdlib.h>
  61. #include <string.h>
  62. #include <sys/file.h>
  63. #include <sys/types.h>
  64. #include <sys/socket.h>
  65. #include <netinet/in.h>
  66. #include <td.h>
  67.  
  68. /*
  69.  * Library imports:
  70.  */
  71.  
  72. extern char *getenv();
  73.  
  74. /*
  75.  * Tokens for the terminal driver, and for the pseudo-device attached
  76.  * to it.
  77.  */
  78.  
  79. static Td_Pdev        pdev;
  80. static Td_Terminal    term;
  81.  
  82. /*
  83.  * Information about the device (the end that connects to the raw
  84.  * RS232 line).
  85.  */
  86.  
  87. int rawInputID;            /* Sprite stream ID used for reading
  88.                  * raw tty. */
  89. int rawOutputID;        /* Sprite stream ID used for writing
  90.                  * raw tty. */
  91. struct sgttyb params;        /* Saved mode bits for device. */
  92. int ttyGroup;            /* Saved controlling group for tty. */
  93.  
  94. /*
  95.  * Buffer used to hold characters waiting to be output.  This is needed
  96.  * because when we retrieve characters from the terminal driver we don't
  97.  * know how many can actually be output to the terminal itself.
  98.  */
  99.  
  100. #define OUT_BUF_SIZE 100
  101. char outputBuffer[OUT_BUF_SIZE];
  102. char *nextOutput;        /* Location of next char. to be output. */
  103. int outputCount = 0;        /* Number of chars. left to output. */
  104. int outputHandler = 0;        /* Non-zero means Fs_Dispatch handler exists
  105.                  * for rawOutputID. */
  106.  
  107. /*
  108.  * Miscellaneous.
  109.  */
  110.  
  111. int exitValue = 0;            /* Exit status for program. */
  112.  
  113. /*
  114.  * Forward references to procedures defined in this file:
  115.  */
  116.  
  117. extern int    Cleanup();
  118. extern int    RawControlProc();
  119. extern void    RawInputProc();
  120. extern void    RawOutputProc();
  121.  
  122. /*
  123.  *----------------------------------------------------------------------
  124.  *
  125.  * main --
  126.  *
  127.  *    Main program for mktty.  Initializes tty setup, waits for things
  128.  *    to happen, calls appropriate handlers.
  129.  *
  130.  * Results:
  131.  *    None.
  132.  *
  133.  * Side effects:
  134.  *    Lots.  See the man page.
  135.  *
  136.  *----------------------------------------------------------------------
  137.  */
  138.  
  139. main(argc, argv)
  140.     int argc;            /* Number of arguments. */
  141.     char **argv;        /* Arguments.  See man page for details. */
  142. {
  143.     char *pdevName, *devName;
  144.     char **args = NULL;
  145.     char *colonPtr;
  146.     int i;
  147.     int applPid;
  148.  
  149.     /*
  150.      *------------------------------
  151.      * Parse command line arguments.
  152.      *------------------------------
  153.      */
  154.  
  155.     if (argc < 2) {
  156.     fprintf(stderr, "Usage: %s device pdev [command]\n", argv[0]);
  157.     Cleanup();
  158.     }
  159.     devName = argv[1];
  160.     pdevName = argv[2];
  161.     if (argc > 3) {
  162.     args = &argv[3];
  163.     }
  164.  
  165.     /*
  166.      *------------------------------------------------------
  167.      * Open the connection to the raw terminal or network.
  168.      *------------------------------------------------------
  169.      */
  170.  
  171.     colonPtr = index(devName, ':');
  172.     if (colonPtr == NULL) {
  173.     if (strcmp(devName, "-") == 0) {
  174.         /*
  175.          * Use standard input and output for the terminal device.
  176.          */
  177.         rawInputID = 0;
  178.         rawOutputID = 1;
  179.     } else {
  180.         /*
  181.          * This is a terminal device.
  182.          */
  183.  
  184.         rawInputID = open(devName, O_RDWR, 0);
  185.         if (rawInputID < 0) {
  186.         fprintf(stderr, "Mktty couldn't open \"%s\": %s.\n",
  187.             devName, strerror(errno));
  188.         exit(1);
  189.         }
  190.         rawOutputID = dup(rawInputID);
  191.     }
  192.     if (ioctl(rawInputID, TIOCGETP, (char *) ¶ms) != 0) {
  193.         fprintf(stderr, "Mktty: \"%s\" isn't a tty.\n", devName);
  194.         exit(1);
  195.     }
  196.     if (ioctl(rawInputID, TIOCGPGRP, (char *) &ttyGroup) != 0) {
  197.         fprintf(stderr, "Mktty couldn't read controlling group: %s\n",
  198.             strerror(errno));
  199.         exit(1);
  200.     }
  201.     i = params.sg_flags;
  202.     params.sg_flags = RAW;
  203.     if (ioctl(rawInputID, TIOCSETP, (char *) ¶ms) != 0) {
  204.         terminalSetupError:
  205.         fprintf(stderr, "Mktty couldn't reset terminal state: %s\n",
  206.             strerror(errno));
  207.         exit(1);
  208.     }
  209.     params.sg_flags = i;
  210.     i = getpgrp(0);
  211.     if (ioctl(rawInputID, TIOCSPGRP, (char *) &i) != 0) {
  212.         goto terminalSetupError;
  213.     }
  214.     if ((fcntl(rawInputID, F_SETFL, FNDELAY) == -1)
  215.         || (fcntl(rawOutputID, F_SETFL, FNDELAY) == -1)) {
  216.         fprintf(stderr, "%s non-blocking mode: %s\n",
  217.             "Mktty couldn't put raw device into",
  218.             strerror(errno));
  219.         exit(1);
  220.     }
  221.     } else {
  222.     /*
  223.      * Network TCP connection:  "host:portNum"
  224.      */
  225.  
  226.     struct hostent *hostPtr;
  227.     struct sockaddr_in serverAddress;
  228.  
  229.     *colonPtr = 0;
  230.     rawInputID = socket(AF_INET, SOCK_STREAM, 0);
  231.     if (rawInputID < 0) {
  232.         perror("Mktty couldn't open socket: %s", strerror(errno));
  233.         exitValue = 1;
  234.         Cleanup();
  235.     }
  236.     rawOutputID = dup(rawInputID);
  237.     bzero((char *) &serverAddress, sizeof(serverAddress));
  238.     serverAddress.sin_family = AF_INET;
  239.     serverAddress.sin_port = htons(atoi(colonPtr+1));
  240.     hostPtr = gethostbyname(devName);
  241.     if (hostPtr == NULL) {
  242.         fprintf(stderr, "Mktty couldn't find a host named \"%s\"\n",
  243.             devName);
  244.         exitValue = 1;
  245.         Cleanup();
  246.     }
  247.     bcopy((char *) hostPtr->h_addr, (char *) &serverAddress.sin_addr,
  248.         sizeof(serverAddress.sin_addr));
  249.     if (connect(rawInputID, (struct sockaddr *) &serverAddress,
  250.         sizeof(serverAddress)) != 0) {
  251.         perror("Mktty couldn't connect to server");
  252.         fprintf(stderr, "This probably means you didn't start a server");
  253.         fprintf(stderr, " process\nor typed the wrong port number\n"); 
  254.         exitValue = 1;
  255.         Cleanup();
  256.     }
  257.     }
  258.  
  259.     /*
  260.      *------------------------------------------------------
  261.      * Set up the pseudo-terminal device.
  262.      *------------------------------------------------------
  263.      */
  264.  
  265.     pdev = Td_CreatePdev(pdevName, (char **) NULL, &term, RawControlProc,
  266.         (ClientData) 0);
  267.     if (pdev == NULL) {
  268.     fprintf(stderr, "Mktty couldn't open pseudo-device \"%s\": %s.\n",
  269.         pdevName, pdev_ErrorMsg);
  270.     exitValue = 1;
  271.     Cleanup();
  272.     }
  273.  
  274.     /*
  275.      *--------------------------------------------------
  276.      * Spawn the application process, if one is desired.
  277.      *--------------------------------------------------
  278.      */
  279.  
  280.     if (args != NULL) {
  281.     Sig_Action old, new;
  282.  
  283.     new.action = SIG_HANDLE_ACTION;
  284.     new.handler = Cleanup;
  285.     new.sigHoldMask = 0;
  286.     Sig_SetAction(SIG_CHILD, &new, &old);
  287.     applPid = fork();
  288.     if (applPid == -1) {
  289.         fprintf(stderr, "Mktty couldn't fork application: %s\n.",
  290.         strerror(errno));
  291.         exitValue = 1;
  292.         Cleanup();
  293.     }
  294.     if (applPid == 0) {
  295.         int ttyID, pid;
  296.         FILE *f;
  297.         char *tty;
  298.  
  299.         tty = getenv("TTY");        /* May be needed below. */
  300.         setenv("TTY", pdevName);
  301.  
  302.         ttyID = open(pdevName, O_RDWR, 0);
  303.         if (ttyID < 0) {
  304.         fprintf(stderr,
  305.             "Mktty couldn't open application end of terminal (%s).\n",
  306.             strerror(errno));
  307.         _exit(1);
  308.         }
  309.         pid = getpid();
  310.         if (setpgrp(0, pid) == -1) {
  311.         fprintf(stderr,
  312.             "Mktty couldn't set process family ID (%s).\n",
  313.             strerror(errno));
  314.         _exit(1);
  315.         }
  316.         if (ioctl(ttyID, TIOCSPGRP, (char *) &pid) != 0) {
  317.         fprintf(stderr,
  318.             "Mktty couldn't set process family for terminal (%s).\n",
  319.             strerror(errno));
  320.         _exit(1);
  321.         }
  322.         dup2(ttyID, 0);
  323.         dup2(ttyID, 1);
  324.         dup2(ttyID, 2);
  325.         for (i = 3; i <= ttyID; i++) {
  326.         close(i);
  327.         }
  328.         execvp(args[0], args);
  329.         if (tty == NULL) {
  330.         _exit(1);
  331.         }
  332.         f = fopen(tty, "w");
  333.         if (f != NULL) {
  334.         fprintf(f, "Couldn't execute \"%s\":\n", args[0],
  335.             strerror(errno));
  336.         }
  337.         _exit(1);
  338.     }
  339.     }
  340.  
  341.     /*
  342.      *--------------------------------------------
  343.      * Enter a loop reading and processing events.
  344.      *--------------------------------------------
  345.      */
  346.  
  347.     Fs_EventHandlerCreate(rawInputID, FS_READABLE, RawInputProc,
  348.         (ClientData) 0);
  349.     while (TRUE) {
  350.     if (outputCount > 0) {
  351.         if (!outputHandler) {
  352.         Fs_EventHandlerCreate(rawOutputID, FS_WRITABLE,
  353.             RawOutputProc, (ClientData) 0);
  354.         outputHandler = 1;
  355.         }
  356.     } else {
  357.         if (outputHandler) {
  358.         Fs_EventHandlerDestroy(rawOutputID);
  359.         outputHandler = 0;
  360.         }
  361.     }
  362.     Fs_Dispatch();
  363.     }
  364. }
  365.  
  366. /*
  367.  *----------------------------------------------------------------------
  368.  *
  369.  * RawInputProc --
  370.  *
  371.  *    This procedure is called by Fs_Dispatch whenever data becomes
  372.  *    readable from the raw tty.  This procedure reads the data
  373.  *    and passes it to the terminal driver.
  374.  *
  375.  * Results:
  376.  *    None.
  377.  *
  378.  * Side effects:
  379.  *    Whatever happens in the terminal driver.
  380.  *
  381.  *----------------------------------------------------------------------
  382.  */
  383.  
  384. void
  385. RawInputProc()
  386. {
  387. #define INPUT_SIZE 100
  388.     char input[INPUT_SIZE];
  389.     int numBytes;
  390.  
  391.     numBytes = read(rawInputID, input, INPUT_SIZE);
  392.     if (numBytes < 0) {
  393.     if (errno == EWOULDBLOCK) {
  394.         return;
  395.     }
  396.     fprintf(stderr, "Mktty couldn't read from device: %s\n",
  397.         strerror(errno));
  398.     exit(1);
  399.     }
  400.     if (numBytes == 0) {
  401.     fprintf(stderr, "Mktty received end-of-file from device.\n");
  402.     fprintf(stderr, "Perhaps network connection was closed or refused?\n");
  403.     exit(1);
  404.     }
  405.     Td_PutRaw(term, numBytes, input);
  406. }
  407.  
  408. /*
  409.  *----------------------------------------------------------------------
  410.  *
  411.  * RawOutputProc --
  412.  *
  413.  *    This procedure is invoked by Fs_Dispatch when the raw tty
  414.  *    becomes writable and there is data in the terminal's output
  415.  *    buffer waiting to be written.
  416.  *
  417.  * Results:
  418.  *    None.
  419.  *
  420.  * Side effects:
  421.  *    Data gets written to the terminal.
  422.  *
  423.  *----------------------------------------------------------------------
  424.  */
  425.  
  426. void
  427. RawOutputProc()
  428. {
  429.     int count;
  430.  
  431.     if (outputCount == 0) {
  432.     return;
  433.     }
  434.     count = write(rawOutputID, nextOutput, outputCount);
  435.     if (count < 0) {
  436.     if (errno != EWOULDBLOCK) {
  437.         fprintf(stderr, "Error writing raw tty: %s.\n", strerror(errno));
  438.         Cleanup();
  439.     }
  440.     return;
  441.     }
  442.     nextOutput += count;
  443.     outputCount -= count;
  444.     if (outputCount == 0) {
  445.     outputCount = Td_GetRaw(term, OUT_BUF_SIZE, outputBuffer);
  446.     nextOutput = outputBuffer;
  447.     }
  448. }
  449.  
  450. /*
  451.  *----------------------------------------------------------------------
  452.  *
  453.  * RawControlProc --
  454.  *
  455.  *    Invoked by the terminal driver to perform control operations
  456.  *    on the raw tty device.
  457.  *
  458.  * Results:
  459.  *    Always returns 0.
  460.  *
  461.  * Side effects:
  462.  *    Varies, depending on the operation.
  463.  *
  464.  *----------------------------------------------------------------------
  465.  */
  466.  
  467.     /* ARGSUSED */
  468. int
  469. RawControlProc(clientData, command, inSize, inBuffer, outSize, outBuffer)
  470.     ClientData clientData;    /* Not used. */
  471.     int command;        /* Identifies control operation being
  472.                  * invoked, e.g. TD_COOKED_SIGNAL. */
  473.     int inSize;            /* Number of bytes of input data available
  474.                  * to us. */
  475.     char *inBuffer;        /* Pointer to input data. */
  476.     int outSize;        /* Maximum number of bytes of output data
  477.                  * we can return to caller. */
  478.     char *outBuffer;        /* Area in which to store output data for
  479.                  * caller. */
  480. {
  481.     switch (command) {
  482.     case TD_RAW_OUTPUT_READY:
  483.         if (outputCount == 0) {
  484.         outputCount = Td_GetRaw(term, OUT_BUF_SIZE, outputBuffer);
  485.         nextOutput = outputBuffer;
  486.         }
  487.         break;
  488.     case TD_RAW_FLUSH_OUTPUT:
  489.         outputCount = 0;
  490.         break;
  491.     }
  492.     return 0;
  493. }
  494.  
  495. /*
  496.  *----------------------------------------------------------------------
  497.  *
  498.  * Cleanup --
  499.  *
  500.  *    This procedure is invoked to restore the terminal state and
  501.  *    exit.  It is called as a signal handler when the child dies,
  502.  *    or at other times when errors occur.
  503.  *
  504.  * Results:
  505.  *    None.
  506.  *
  507.  * Side effects:
  508.  *    This process dies.  The terminal's state gets restored.
  509.  *
  510.  *----------------------------------------------------------------------
  511.  */
  512.  
  513. Cleanup()
  514. {
  515.     if (pdev != NULL) {
  516.     Td_DeletePdev(pdev);
  517.     }
  518.     ioctl(rawInputID, TIOCSETP, (char *) ¶ms);
  519.     ioctl(rawInputID, TIOCSPGRP, (char *) &ttyGroup);
  520.     exit(exitValue);
  521. }
  522. @
  523.  
  524.  
  525. 1.1
  526. log
  527. @Initial revision
  528. @
  529. text
  530. @d20 1
  531. a20 1
  532. static char rcsid[] = "$Header: /a/newcmds/tty/RCS/tty.c,v 1.4 88/09/28 17:14:36 ouster Exp Locker: ouster $ SPRITE (Berkeley)";
  533. d26 1
  534. d186 7
  535. d365 3
  536. @
  537.